package org.sardine.beans;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.sardine.beans.support.BeanObjectInstantiation;
import org.sardine.beans.support.ElmBeanDefinition;
import org.sardine.beans.support.ElmBeanDefinitionRegistry;
import org.sardine.beans.support.ElmPropertyDefinition;
import org.sardine.beans.support.ListType;
import org.sardine.beans.support.MapType;
import org.sardine.beans.support.RefType;
import org.sardine.beans.support.SetType;
import org.sardine.util.Assert;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

public class SimpleXmlDefinitionParser implements XmlParser {
	
	private final Logger log = Logger.getLogger(getClass());
	
	private final static String BEANS = "beans";
	private final static String BEAN = "bean";
	private final static String BEAN_ID = "id";
	private final static String BEAN_CLASS = "class";
	private final static String PROPERTY = "property";
	public final static String PROPERTY_NAME = "name";
	private final static String PROPERTY_VALUE = "value";
	private final static String PROPERTY_REF = "ref";
	private final static String LIST = "list";
	private final static String SET = "set";
	private final static String MAP = "map";
	private final static String VALUE = "value";
	private final static String REF = "ref";
	private final static String ENTRY = "entry";
	private final static String ENTRY_KEY = "key";
	private final static String ENTRY_VALUE = "value";
	private final static String ENTRY_REF = "ref";
	//private final Map beanObjects = Collections.synchronizedMap(new HashMap(16));
	//private final Map<String,ElmBeanDefinition> beanDefinitions = new HashMap<String,ElmBeanDefinition>();
	private final ElmBeanDefinitionRegistry registry;
	
	public SimpleXmlDefinitionParser(ElmBeanDefinitionRegistry elmBeanDefinitionRegistry){
		this.registry = elmBeanDefinitionRegistry;
	}
	
	public void parseDocument(Document doc) {
		Assert.notNull(doc, "Document 不能为空");
		
		Element root = doc.getDocumentElement();
		
		if(BEANS.equals(root.getTagName())){
			NodeList beans = root.getElementsByTagName(BEAN);
			int length = beans.getLength();
			for(int i=0;i<length;i++){
				Node beanNode = beans.item(i);
				if(beanNode instanceof Element){
					doParseBean((Element)beanNode);
				}
			}
		}

	}

	/**
	 * 
	 * 解析<bean>
	 * 
	 * @param bean
	 */
	protected void doParseBean(Element bean) {
		Assert.notNull(bean, "bean 不能为空");
		BeanObjectInstantiation objFactory = new BeanObjectInstantiation();
		
		if(BEAN.equals(bean.getTagName())){
			
			Object beanObject = null;
			
			//NamedNodeMap attributes = bean.getAttributes();
			//String id = attributes.getNamedItem(BEAN_ID).getNodeValue();
			//String clazz = attributes.getNamedItem(BEAN_CLASS).getNodeValue();
			String id = bean.getAttribute(BEAN_ID);
			String clazz = bean.getAttribute(BEAN_CLASS);
			log.debug("开始解析<bean id=\""+id+"\" class=\""+clazz+"\" />");
			/*if(beanObjects.get(id) == null){
				beanObject = objFactory.createObject(clazz);
			}*/
			ElmBeanDefinition beanDef = null;
			if(!registry.containsElmBeanDefinition(id)){
				beanDef = new ElmBeanDefinition(id,clazz);	
			}else{
				beanDef = registry.getElmBeanDefinition(id);
			}
			
			//NodeList properties = bean.getChildNodes();
			NodeList properties = bean.getElementsByTagName(PROPERTY);
			int length = properties.getLength();
			for(int i=0;i<length;i++){
				Node propertyNode = properties.item(i);
				if(propertyNode instanceof Element){
					doParseProperty((Element)propertyNode,beanDef);
				}
			}
			registry.registerElmBeanDefinition(id, beanDef);
		}

	}
	
	/**
	 * 
	 * 解析<property>
	 * 
	 * @param property
	 * @param beanDef
	 */
	protected void doParseProperty(Element property,ElmBeanDefinition beanDef){
		Assert.notNull(property, "property 不能为空");
		
		if(PROPERTY.equals(property.getTagName())){
			
			//NamedNodeMap attributes = property.getAttributes();
			//String name = parseAttribute(attributes,PROPERTY_NAME);
			//String value = parseAttribute(attributes,PROPERTY_VALUE);
			//String ref = parseAttribute(attributes,PROPERTY_REF);
			String name = property.getAttribute(PROPERTY_NAME);
			String value = property.getAttribute(PROPERTY_VALUE);
			String ref = property.getAttribute(PROPERTY_REF);
			log.debug("开始解析<property name=\""+name+"\" value=\""+value+"\"ref=\""+ref+"\" />");
			
			ElmPropertyDefinition propertyDef = null;
			/*
			 * 如果元素的属性为空，Element.getAttribute()返回的值时"",而不是null,所以要判断长度
			 */
			if(ref != null && ref.length() > 0){
				RefType refType = new RefType(ref);
				propertyDef = new ElmPropertyDefinition(name,refType);
			}else if(value != null && value.length() > 0){
				propertyDef = new ElmPropertyDefinition(name,value);
			}else{
				
				NodeList nl = property.getChildNodes();
				for(int i=0;i<nl.getLength();i++){
					Node specialValueNode = nl.item(i);
					if(specialValueNode instanceof Element){
						String elmName = specialValueNode.getNodeName();
						
						if(elmName.equals(LIST)){
							propertyDef = new ElmPropertyDefinition(name,doParseList((Element)specialValueNode));
							
						}else if(elmName.equals(SET)){
							propertyDef = new ElmPropertyDefinition(name,doParseSet((Element)specialValueNode));
							
						}else if(elmName.equals(MAP)){
							propertyDef = new ElmPropertyDefinition(name,doParseMap((Element)specialValueNode));
							
						}else if(elmName.equals(VALUE)){
							propertyDef = new ElmPropertyDefinition(name,doParseValue((Element)specialValueNode));
						}else{
							throw new XmlDefinitionParserException("<"+elmName+"/>是非法的元素，请从XML文件中删除");
						}
						break;// <property>只能有一个子元素
					}
				}
			}
			
			if(propertyDef != null){
				beanDef.addProperty(propertyDef);
			}
		}
		
	}
	
	/**
	 * 
	 * 解析<list>
	 * 
	 * @param listValue
	 * @return
	 */
	protected Object doParseList(Element listValue){
		NodeList values = listValue.getChildNodes();
		ListType listType = new ListType();
		for(int i=0;i<values.getLength();i++){
			Node valueNode = values.item(i);
			if(valueNode instanceof Element){
				if(VALUE.equals(valueNode.getNodeName())){
					listType.add(valueNode.getTextContent());
				}else if(REF.equals(valueNode.getNodeName())){
					listType.add(new RefType(valueNode.getTextContent()));
				}else{
					throw new XmlDefinitionParserException("<"+valueNode.getNodeName()+"/>是非法的元素，请从XML文件中删除");
				}
			}	
		}
		return listType;
		
	}
	
	/**
	 * 
	 * 解析<set>
	 * 
	 * @param setValue
	 * @return
	 */
	protected Object doParseSet(Element setValue){
		NodeList values = setValue.getChildNodes();
		SetType setType = new SetType();
		for(int i=0;i<values.getLength();i++){
			Node valueNode = values.item(i);
			if(valueNode instanceof Element){
				if(VALUE.equals(valueNode.getNodeName())){
					setType.add(valueNode.getTextContent());
				}else if(REF.equals(valueNode.getNodeName())){
					setType.add(new RefType(valueNode.getTextContent()));
				}else{
					throw new XmlDefinitionParserException("<"+valueNode.getNodeName()+"/>是非法的元素，请从XML文件中删除");
				}
			}
		}
		return setType;
	}

	/**
	 * 
	 * 解析<map>
	 * 
	 * @param mapValue
	 * @return
	 */
	protected Object doParseMap(Element mapValue){
		NodeList values = mapValue.getChildNodes();
		MapType mapType = new MapType();
		for(int i=0;i<values.getLength();i++){
			Node valueNode = values.item(i);
			if(valueNode instanceof Element){
				if(ENTRY.equals(valueNode.getNodeName())){
					Element entry = (Element)valueNode;
					String key = entry.getAttribute(ENTRY_KEY);
					String value = entry.getAttribute(ENTRY_VALUE);
					String ref = entry.getAttribute(ENTRY_REF);
					/*
					 * 如果元素的属性为空，Element.getAttribute()返回的值是"",而不是null,所以要判断长度
					 */
					if(ref != null && ref.length() > 0){
						mapType.put(key, new RefType(ref));
					}else if(value != null && value.length() > 0){
						mapType.put(key, value);
					}else{
						throw new XmlDefinitionParserException("<"+valueNode.getNodeName()+"/>元素缺少必备属性ref或value，请重新设置");
					}
				}else{
					throw new XmlDefinitionParserException("<"+valueNode.getNodeName()+"/>是非法的元素，请从XML文件中删除");
				}
			}
		}
		return mapType;
	}
	
	protected String doParseValue(Element valueValue){
		NodeList values = valueValue.getChildNodes();
		for(int i=0;i<values.getLength();i++){
			Node valueNode = values.item(i);
			if(valueNode instanceof Text){
				String textValue = ((Text)valueNode).getWholeText();
				return textValue.trim();
			}
		}
		return "";
	}
	
	@Deprecated
	protected String parseAttribute(NamedNodeMap attributes,String attributeName){
		
		Node attribute = attributes.getNamedItem(attributeName);
		if(attribute != null){
			return attribute.getNodeValue();
		}else{
			return null;
		}
		
	}

}
